//////////////////////////////////////////////////////////////////////
// IImgSampler.h
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Basic image sampler class,
//	provides pixel-wise and bilinear filtering tex2D access.
//
//  (u,v) origin is at the upper-left corner
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include <ImgTmpl.h>
#include <ImgMath.h>

namespace grflib
{
	namespace image
	{
		template<typename T>
		class IImgSampler
		{
		public:
			IImgSampler(void);
			virtual ~IImgSampler(void);

			////////////////////////////////
			//Content binding
			virtual void BindImage(w32lib::CImgTmpl<T> *pImg);

			////////////////////////////////
			//General info
			UINT GetBPP(void);
			UINT GetWidth(void);
			UINT GetHeight(void);

			////////////////////////////////
			//General texture accessing
			T &operator() (const UINT &x, const UINT &y, const UINT &c);
			const T &operator() (const UINT &x, const UINT &y, const UINT &c) const;

			T tex2D(const float &u, const float &v, const UINT &c); //bilinear interpolation

		protected:
			w32lib::CImgTmpl<T> *m_pImg;
			UINT m_width;
			UINT m_height;
			UINT m_bpp;
		};


		template<typename T>
		IImgSampler<T>::IImgSampler() :
			m_width(0),
			m_height(0),
			m_bpp(0),
			m_pImg(0)
		{
		}

		template<typename T>
		IImgSampler<T>::~IImgSampler()
		{
		}

		template<typename T>
		UINT IImgSampler<T>::GetBPP()
		{
			return m_bpp;
		}

		template<typename T>
		UINT IImgSampler<T>::GetWidth()
		{
			return m_width;
		}

		template<typename T>
		UINT IImgSampler<T>::GetHeight()
		{
			return m_height;
		}

		template<typename T>
		T &IImgSampler<T>::operator()(const UINT &x, const UINT &y, const UINT &c)
		{
			//not checking m_pImg != 0 in release mode for performance concern
			_ASSERT(m_pImg != 0);
			return (*m_pImg)(x, y, c);
		}

		template<typename T>
		const T &IImgSampler<T>::operator()(const UINT &x, const UINT &y, const UINT &c) const
		{
			//not checking m_pImg != 0 in release mode for performance concern
			_ASSERT(m_pImg != 0);
			return (*m_pImg)(x, y, c);
		}

		//tex2D with bilinear interpolation
		template<typename T>
		T IImgSampler<T>::tex2D(const float &u, const float &v, const UINT &c)
		{
			_ASSERT(m_pImg != 0 && m_width != 0 && m_height != 0);

			float xf, yf;
			UINT x0, y0, x1, y1;

			//xf = u * (m_width - 1) ; yf = v * (m_height - 1) ;
            xf = u * m_width - 0.5f; yf = v * m_height - 0.5f;
			x0 = (UINT)math::Saturate(floor(xf), 0.0f, m_width - 1.0f);
			y0 = (UINT)math::Saturate(floor(yf), 0.0f, m_height - 1.0f);
			x1 = (UINT)math::Saturate(ceil(xf), 0.0f, m_width - 1.0f);
			y1 = (UINT)math::Saturate(ceil(yf), 0.0f, m_height - 1.0f);

			float w[4] = {0};
			math::BilinearWeight(xf, yf, w);

			T result = (T)((*m_pImg)(x0, y0, c) * w[0]
			+ (*m_pImg)(x1, y0, c) * w[1]
			+ (*m_pImg)(x0, y1, c) * w[2]
			+ (*m_pImg)(x1, y1, c) * w[3]);

			return result;
		}

		template<typename T>
		void IImgSampler<T>::BindImage(w32lib::CImgTmpl<T> *pImg)
		{
			_ASSERT(pImg != 0);
			m_width = pImg->GetWidth();
			m_height = pImg->GetHeight();
			m_bpp = pImg->GetBPP();
			m_pImg = pImg;
		}
	} //namespace namespace image
} //namespace namespace grflib